/**
 * // Copyright (c) 2023 KylinOS. All rights reserved.
 * //
 * // This program is free software; you can redistribute it
 * // and/or modify it under the terms of the GNU General Public
 * // License (version 2) as published by the FSF - Free Software
 * // Foundation*
 */

/**
 * // Copyright (C) 2023 ben LG <guoliben@kylinos.cn>
 */

package docextractor

import (
	"bytes"
	"os/exec"
	"time"

	"github.com/ledongthuc/pdf"

	"gitee.com/guoliben/kydlp-doctotext/extractor_interface"
	"gitee.com/guoliben/kydlp-doctotext/utils/ctrlledprint"
)

type DocPdf struct{}

func (extractor DocPdf) GetTextFromFile(path string, size int64, filetype string, depth int) ([]byte, string) {
	ctrlledprint.Println("提取文本: 正在解析pdf(file)文档...")

	defer func() error {
		if r := recover(); r != nil {
			return nil
		}
		return nil
	}()

	start := time.Now()

	file, r, err := pdf.Open(path)
	if err != nil {
		ctrlledprint.Println("Error opening pdf file:", err)
		return nil, ""
	}
	defer file.Close()

	var text []byte
	var b bytes.Buffer
	totalPages := r.NumPage()
	//ctrlledprint.Printf("PDF 文件: \"%s\" 共有 %d 页\n", path, numPages)
	for i := 1; i <= totalPages; i++ {
		page := r.Page(i)
		if page.V.IsNull() {
			continue
		}
		plaintext, err := page.GetPlainText(nil)
		if err != nil {
			ctrlledprint.Println("Error reading pdf file:", err)
			continue
		}
		//ctrlledprint.Printf("第 %d 页内容:\n%s\n", i, plaintext)
		b.WriteString(plaintext)
	}
	text = b.Bytes()

	elapsed := time.Since(start)

	return text, elapsed.String()
}

func (extractor DocPdf) GetTextFromBuffer(path string, data []byte, size int64, filetype string, depth int) ([]byte, string) {
	ctrlledprint.Println("提取文本: 正在解析pdf(buffer)文档...")

	defer func() error {
		if r := recover(); r != nil {
			return nil
		}
		return nil
	}()

	start := time.Now()

	//r, err := pdf.NewReader(bytes.NewReader(data), size)
	r, err := pdf.NewReader(bytes.NewReader(data), int64(len(data)))
	if err != nil {
		ctrlledprint.Println("Error creating pdf reader:", err)
		return nil, ""
	}

	var text []byte
	var b bytes.Buffer
	totalPages := r.NumPage()
	//ctrlledprint.Printf("PDF 文件: \"%s\" 共有 %d 页\n", path, numPages)
	for i := 1; i <= totalPages; i++ {
		page := r.Page(i)
		if page.V.IsNull() {
			continue
		}
		plaintext, err := page.GetPlainText(nil)
		if err != nil {
			ctrlledprint.Println("Error reading pdf file:", err)
			continue
		}
		//ctrlledprint.Printf("第 %d 页内容:\n%s\n", i, plaintext)
		b.WriteString(plaintext)
	}
	text = b.Bytes()

	elapsed := time.Since(start)

	return text, elapsed.String()
}

func (extractor DocPdf) GetStringTextFromFile(path string, size int64, filetype string, depth int) (string, string) {
	ctrlledprint.Println("提取文本: 正在解析pdf(file)文档...")

	defer func() error {
		if r := recover(); r != nil {
			return nil
		}
		return nil
	}()

	start := time.Now()

	file, r, err := pdf.Open(path)
	if err != nil {
		ctrlledprint.Println("Error opening pdf file:", err)
		return "", ""
	}
	defer file.Close()

	var text string
	var b bytes.Buffer
	totalPages := r.NumPage()
	//ctrlledprint.Printf("PDF 文件: \"%s\" 共有 %d 页\n", path, numPages)
	for i := 1; i <= totalPages; i++ {
		page := r.Page(i)
		if page.V.IsNull() {
			continue
		}
		plaintext, err := page.GetPlainText(nil)
		if err != nil {
			ctrlledprint.Println("Error reading pdf file:", err)
			continue
		}
		//ctrlledprint.Printf("第 %d 页内容:\n%s\n", i, plaintext)
		b.WriteString(plaintext)
	}
	text = b.String()

	elapsed := time.Since(start)

	return text, elapsed.String()
}

func (extractor DocPdf) GetStringTextFromBuffer(path string, data []byte, size int64, filetype string, depth int) (string, string) {
	ctrlledprint.Println("提取文本: 正在解析pdf(buffer)文档...")

	defer func() error {
		if r := recover(); r != nil {
			return nil
		}
		return nil
	}()

	start := time.Now()

	//r, err := pdf.NewReader(bytes.NewReader(data), size)
	r, err := pdf.NewReader(bytes.NewReader(data), int64(len(data)))
	if err != nil {
		ctrlledprint.Println("Error creating pdf reader:", err)
		return "", ""
	}

	var text string
	var b bytes.Buffer
	totalPages := r.NumPage()
	//ctrlledprint.Printf("PDF 文件: \"%s\" 共有 %d 页\n", path, numPages)
	for i := 1; i <= totalPages; i++ {
		page := r.Page(i)
		if page.V.IsNull() {
			continue
		}
		plaintext, err := page.GetPlainText(nil)
		if err != nil {
			ctrlledprint.Println("Error reading pdf file:", err)
			continue
		}
		//ctrlledprint.Printf("第 %d 页内容:\n%s\n", i, plaintext)
		b.WriteString(plaintext)
	}
	text = b.String()

	elapsed := time.Since(start)

	return text, elapsed.String()
}

func pdfProcessFile(path string) ([]byte, error) {
	// 构建PDF任务处理器命令及其参数
	cmd := exec.Command("/opt/kydlp-control-discovery/bin/kydlp-tasktransfer", "--socket", unixSocketPath, "--task", "pdftask", "--file", path)

	// 缓冲区用于存储命令的输出
	var out bytes.Buffer
	var errOut bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &errOut

	// 执行命令并等待其完成
	if err := cmd.Run(); err != nil {
		ctrlledprint.Println("执行kydlp-tasktransfer命令处理PDF(file)任务出错:", errOut.String())
		return nil, err
	} else {
		ctrlledprint.Println("执行kydlp-tasktransfer命令处理PDF(file)任务成功，输出:", out.String())
		return out.Bytes(), nil
	}
}

func pdfProcessBuffer(path string) ([]byte, error) {
	// 构建PDF任务处理器命令及其参数
	cmd := exec.Command("/opt/kydlp-control-discovery/bin/kydlp-tasktransfer", "--socket", unixSocketPath, "--task", "pdftask", "--buffer")

	// 缓冲区用于存储命令的输出
	var out bytes.Buffer
	var errOut bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &errOut

	// 执行命令并等待其完成
	if err := cmd.Run(); err != nil {
		ctrlledprint.Println("执行kydlp-tasktransfer命令处理PDF(buffer)任务出错:", errOut.String())
		return nil, err
	} else {
		ctrlledprint.Println("执行kydlp-tasktransfer命令处理PDF(buffer)任务成功，输出:", out.String())
		return out.Bytes(), nil
	}
}

func pdfProcessFileReturnString(path string) (string, error) {
	// 构建PDF任务处理器命令及其参数
	cmd := exec.Command("/opt/kydlp-control-discovery/bin/kydlp-tasktransfer", "--socket", unixSocketPath, "--task", "pdftask", "--file", path)

	// 缓冲区用于存储命令的输出
	var out bytes.Buffer
	var errOut bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &errOut

	// 执行命令并等待其完成
	if err := cmd.Run(); err != nil {
		ctrlledprint.Println("执行kydlp-tasktransfer命令处理PDF(file)任务出错:", errOut.String())
		return "", err
	} else {
		ctrlledprint.Println("执行kydlp-tasktransfer命令处理PDF(file)任务成功，输出:", out.String())
		return out.String(), nil
	}
}

func pdfProcessBufferReturnString(path string) (string, error) {
	// 构建PDF任务处理器命令及其参数
	cmd := exec.Command("/opt/kydlp-control-discovery/bin/kydlp-tasktransfer", "--socket", unixSocketPath, "--task", "pdftask", "--buffer")

	// 缓冲区用于存储命令的输出
	var out bytes.Buffer
	var errOut bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &errOut

	// 执行命令并等待其完成
	if err := cmd.Run(); err != nil {
		ctrlledprint.Println("执行kydlp-tasktransfer命令处理PDF(buffer)任务出错:", errOut.String())
		return "", err
	} else {
		ctrlledprint.Println("执行kydlp-tasktransfer命令处理PDF(buffer)任务成功，输出:", out.String())
		return out.String(), nil
	}
}

func pdfGetTextFromFile(path string, size int64, filetype string) ([]byte, string) {
	ctrlledprint.Println("提取文本: 正在解析pdf(file)文档...")

	start := time.Now()

	text, _ := pdfProcessFile(path)

	elapsed := time.Since(start)

	return text, elapsed.String()
}

func pdfGetTextFromBuffer(path string, data []byte, size int64, filetype string) ([]byte, string) {
	ctrlledprint.Println("提取文本: 正在解析pdf(buffer)文档...")

	pdftask := DocumentBufferTask{
		FileContent: data,
		FileSize: size,
		FileType: filetype,
	}
	err := PdfBufferTaskQueue.Enqueue(pdftask)
	if err != nil {
		ctrlledprint.Println("PDF(buffer)文档任务入队失败:", err)
		return nil, ""
	} else {
		ctrlledprint.Println("PDF(buffer)文档任务入队成功!")
	}
	ctrlledprint.Println("---> PDF(buffer)文档任务队列容量:", PdfBufferTaskQueue.GetCap(), "已经入队的任务数:", PdfBufferTaskQueue.GetLen())

	start := time.Now()

	text, _ := pdfProcessBuffer(path)

	elapsed := time.Since(start)

	return text, elapsed.String()
}

func pdfGetStringTextFromFile(path string, size int64, filetype string) (string, string) {
	ctrlledprint.Println("提取文本: 正在解析pdf(file)文档...")

	start := time.Now()

	text, _ := pdfProcessFileReturnString(path)

	elapsed := time.Since(start)

	return text, elapsed.String()
}

func pdfGetStringTextFromBuffer(path string, data []byte, size int64, filetype string) (string, string) {
	ctrlledprint.Println("提取文本: 正在解析pdf(buffer)文档...")

	pdftask := DocumentBufferTask{
		FileContent: data,
		FileSize: size,
		FileType: filetype,
	}
	err := PdfBufferTaskQueue.Enqueue(pdftask)
	if err != nil {
		ctrlledprint.Println("PDF(buffer)文档任务入队失败:", err)
		return "", ""
	} else {
		ctrlledprint.Println("PDF(buffer)文档任务入队成功!")
	}
	ctrlledprint.Println("---> PDF(buffer)文档任务队列容量:", PdfBufferTaskQueue.GetCap(), "已经入队的任务数:", PdfBufferTaskQueue.GetLen())

	start := time.Now()

	text, _ := pdfProcessBufferReturnString(path)

	elapsed := time.Since(start)

	return text, elapsed.String()
}

func (extractor DocPdf) GetTextFromFileWithCallback(path string, size int64, filetype string, depth int, callback extractor_interface.OnTextDetectHandler, context interface{}) (int, []byte, string) {
	var retcode int
	var text []byte
	var elapsed string

	if multiProcessMode {
		text, elapsed = pdfGetTextFromFile(path, size, filetype)
	} else {
		text, elapsed = extractor.GetTextFromFile(path, size, filetype, depth)
	}

	if callback != nil {
		retcode, _ = callback(path, size, filetype, text, int64(len(text)), context)
	}

	return retcode, text, elapsed
}

func (extractor DocPdf) GetTextFromBufferWithCallback(path string, data []byte, size int64, filetype string, depth int, callback extractor_interface.OnTextDetectHandler, context interface{}) (int, []byte, string) {
	var retcode int
	var text []byte
	var elapsed string

	if multiProcessMode {
		text, elapsed = pdfGetTextFromBuffer(path, data, size, filetype)
	} else {
		text, elapsed = extractor.GetTextFromBuffer(path, data, size, filetype, depth)
	}

	if callback != nil {
		retcode, _ = callback(path, size, filetype, text, int64(len(text)), context)
	}

	return retcode, text, elapsed
}

func (extractor DocPdf) GetStringTextFromFileWithCallback(path string, size int64, filetype string, depth int, callback extractor_interface.OnStringTextDetectHandler, context interface{}) (int, string, string) {
	var retcode int
	var text, elapsed string

	if multiProcessMode {
		text, elapsed = pdfGetStringTextFromFile(path, size, filetype)
	} else {
		text, elapsed = extractor.GetStringTextFromFile(path, size, filetype, depth)
	}

	if callback != nil {
		retcode, _ = callback(path, size, filetype, text, int64(len(text)), context)
	}

	return retcode, text, elapsed
}

func (extractor DocPdf) GetStringTextFromBufferWithCallback(path string, data []byte, size int64, filetype string, depth int, callback extractor_interface.OnStringTextDetectHandler, context interface{}) (int, string, string) {
	var retcode int
	var text, elapsed string

	if multiProcessMode {
		text, elapsed = pdfGetStringTextFromBuffer(path, data, size, filetype)
	} else {
		text, elapsed = extractor.GetStringTextFromBuffer(path, data, size, filetype, depth)
	}

	if callback != nil {
		retcode, _ = callback(path, size, filetype, text, int64(len(text)), context)
	}

	return retcode, text, elapsed
}
